module Interpretador
(
	table,
	avalExpr,
	expression,
    infix_to_prefix,
) where


import Tipos


table = [("x", Int_v 0)]
--soma = Set "x" (Sum (Constant (Int_v 2) Int_t) (Constant (Real_v 2.0) Int_t)) 
--y = avalExpr soma table

-- Avalia as expressões
avalExpr :: Expr -> [(String, Value)] -> ([(String, Value)], Value)
avalExpr expr table = 
	case expr of
		Constant v t -> (table, v)

		Sum e1 e2 -> 
			let (new_table, a) = avalExpr e1 table in
			let (new_table2, b) = avalExpr e2 new_table in
			case (b, a) of
				(Int_v v1, Real_v v2) -> (new_table2, Real_v (fromIntegral v1 + v2))
				(Real_v v1, Int_v v2) -> (new_table2, Real_v (v1 + fromIntegral v2))
				(Real_v v1, Real_v v2) -> (new_table2, Real_v (v1 + v2))
				(Int_v v1, Int_v v2) -> (new_table2, Int_v (v1 + v2))
				_ -> (new_table2, Int_v 999999)

		Sub e1 e2 -> 
			let (new_table, a) = avalExpr e1 table in
			let (new_table2, b) = avalExpr e2 new_table in
			case (b, a) of
				(Int_v v1, Real_v v2) -> (new_table2, Real_v (fromIntegral v1 - v2))
				(Real_v v1, Int_v v2) -> (new_table2, Real_v (v1 - fromIntegral v2))
				(Real_v v1, Real_v v2) -> (new_table2, Real_v (v1 - v2))
				(Int_v v1, Int_v v2) -> (new_table2, Int_v (v1 - v2))
				_ -> (new_table2, Int_v 999999)

		Mul e1 e2 -> 
			let (new_table, a) = avalExpr e1 table in
			let (new_table2, b) = avalExpr e2 new_table in
			case (b, a) of
				(Int_v v1, Real_v v2) -> (new_table2, Real_v (fromIntegral v1 * v2))
				(Real_v v1, Int_v v2) -> (new_table2, Real_v (v1 * fromIntegral v2))
				(Real_v v1, Real_v v2) -> (new_table2, Real_v (v1 * v2))
				(Int_v v1, Int_v v2) -> (new_table2, Int_v (v1 * v2))
				_ -> (new_table2, Int_v 999999)

		Div e1 e2 -> 
			let (new_table, a) = avalExpr e1 table in
			let (new_table2, b) = avalExpr e2 new_table in
			case (b, a) of
				(Int_v v1, Real_v v2) -> (new_table2, Real_v (fromIntegral v1 / v2))
				(Real_v v1, Int_v v2) -> (new_table2, Real_v (v1 / fromIntegral v2))
				(Real_v v1, Real_v v2) -> (new_table2, Real_v (v1 / v2))
				(Int_v v1, Int_v v2) -> (new_table2, Int_v (floor((fromIntegral v1) / (fromIntegral v2))))
				_ -> (new_table2, Int_v 999999)

		Expo e1 e2 -> 
			let (new_table, a) = avalExpr e1 table in
			let (new_table2, b) = avalExpr e2 new_table in
			case (b, a) of
				(Int_v v1, Real_v v2) -> (new_table2, Real_v (fromIntegral v1 ** v2))
				(Real_v v1, Int_v v2) -> (new_table2, Real_v (v1 ** fromIntegral v2))
				(Real_v v1, Real_v v2) -> (new_table2, Real_v (v1 ** v2))
				(Int_v v1, Int_v v2) -> (new_table2, Real_v (fromIntegral v1 ** fromIntegral v2))
				_ -> (new_table2, Int_v 999999)

		Set str exp ->
			let (a, b) = avalExpr exp table in
			((auxt str a b), Int_v 0)

		_ -> (table, Int_v 0)

auxt s table v = 
	case table of
		[] -> []
		(name, value):tl ->
			if name == s then
				(name, v):tl
			else
				(name, value):(auxt s tl v)

infix_to_prefix :: [Token] -> [Tk] -> [Token] -> (Bool, [Token])
infix_to_prefix i stack result =
        case i of
            [] -> 
                case stack of
                    [] -> (True, result)
                    a:b -> infix_to_prefix [] b ((a, 0):result)
            ((Int_tk v), l0):tl -> infix_to_prefix tl stack ((Int_tk v, l0):result)
            ((Bool_tk v), l0):tl -> infix_to_prefix tl stack ((Bool_tk v, l0):result)
            ((Char_tk v), l0):tl -> infix_to_prefix tl stack ((Char_tk v, l0):result)
            ((Float_tk v), l0):tl -> infix_to_prefix tl stack ((Float_tk v, l0):result)
            ((String_tk v), l0):tl -> infix_to_prefix tl stack ((String_tk v, l0):result)
            ((LP_tk), l0):tl -> infix_to_prefix tl (LP_tk:stack) result
            ((RP_tk), l0):tl -> 
                case stack of
                    [] -> (False, [])
                    LP_tk:tli -> infix_to_prefix tl tli result
                    hdi:tli -> infix_to_prefix i tli ((hdi, 0):result)
            ((Minus_tk), l0):tl -> 
                case stack of
                    [] -> infix_to_prefix tl [Minus_tk] result
                    Exp_tk:tli -> infix_to_prefix i tli ((Exp_tk, l0):result)
                    Div_tk:tli -> infix_to_prefix i tli ((Div_tk, l0):result)
                    Mult_tk:tli -> infix_to_prefix i tli ((Mult_tk, l0):result)
                    Plus_tk:tli -> infix_to_prefix i tli ((Plus_tk, l0):result)
                    Minus_tk:tli -> infix_to_prefix i tli ((Minus_tk, l0):result)
                    LP_tk:tli -> infix_to_prefix tl (Minus_tk:stack) result
            ((Plus_tk), l0):tl -> 
                case stack of
                    [] -> infix_to_prefix tl [Plus_tk] result
                    Exp_tk:tli -> infix_to_prefix i tli ((Exp_tk, l0):result)
                    Div_tk:tli -> infix_to_prefix i tli ((Div_tk, l0):result)
                    Mult_tk:tli -> infix_to_prefix i tli ((Mult_tk, l0):result)
                    Plus_tk:tli -> infix_to_prefix i tli ((Plus_tk, l0):result)
                    Minus_tk:tli -> infix_to_prefix tl (Plus_tk:stack) result
                    LP_tk:tli -> infix_to_prefix tl (Plus_tk:stack) result
            ((Mult_tk), l0):tl -> 
                case stack of
                    [] -> infix_to_prefix tl [Mult_tk] result
                    Exp_tk:tli -> infix_to_prefix i tli ((Exp_tk, l0):result)
                    Div_tk:tli -> infix_to_prefix i tli ((Div_tk, l0):result)
                    Mult_tk:tli -> infix_to_prefix i tli ((Mult_tk, l0):result)
                    Plus_tk:tli -> infix_to_prefix tl (Mult_tk:stack) result
                    Minus_tk:tli -> infix_to_prefix tl (Mult_tk:stack) result
                    LP_tk:tli -> infix_to_prefix tl (Mult_tk:stack) result
            ((Div_tk), l0):tl -> 
                case stack of
                    [] -> infix_to_prefix tl [Div_tk] result
                    Exp_tk:tli -> infix_to_prefix i tli ((Exp_tk, l0):result)
                    Div_tk:tli -> infix_to_prefix i tli ((Div_tk, l0):result)
                    Mult_tk:tli -> infix_to_prefix tl (Div_tk:stack) result
                    Plus_tk:tli -> infix_to_prefix tl (Div_tk:stack) result
                    Minus_tk:tli -> infix_to_prefix tl (Div_tk:stack) result
                    LP_tk:tli -> infix_to_prefix tl (Div_tk:stack) result
            ((Exp_tk), l0):tl -> 
                case stack of
                    [] -> infix_to_prefix tl [Exp_tk] result
                    Exp_tk:tli -> infix_to_prefix i tli ((Exp_tk, l0):result)
                    Div_tk:tli -> infix_to_prefix tl (Exp_tk:stack) result
                    Mult_tk:tli -> infix_to_prefix tl (Exp_tk:stack) result
                    Plus_tk:tli -> infix_to_prefix tl (Exp_tk:stack) result
                    Minus_tk:tli -> infix_to_prefix tl (Exp_tk:stack) result
                    LP_tk:tli -> infix_to_prefix tl (Exp_tk:stack) result
            a:b -> infix_to_prefix b stack result

expression :: [Token] -> (Bool, [Token], Expr)
expression expr =
	case expr of
        [] -> (False, [], (Constant (Int_v 999999) Int_t))
        (Int_tk v, l0):tl -> (True, tl, (Constant (Int_v v) Int_t))
        (Float_tk v, l0):tl -> (True, tl, (Constant (Real_v v) Real_t))
        (Bool_tk v, l0):tl -> (True, tl, (Constant (Bool_v v) Bool_t))
        (Char_tk v, l0):tl -> (True, tl, (Constant (Char_v v) Char_t))
        (Plus_tk, l0):tl -> 
   			let (a,b,c) = expression tl in
   			let (d,e,f) = expression b in
			(a, e, (Sum c f))
        (Minus_tk, l0):tl -> 
   			let (a,b,c) = expression tl in
   			let (d,e,f) = expression b in
			(a, e, (Sub c f))
        (Mult_tk, l0):tl -> 
   			let (a,b,c) = expression tl in
   			let (d,e,f) = expression b in
			(a, e, (Mul c f))
        (Div_tk, l0):tl -> 
   			let (a,b,c) = expression tl in
   			let (d,e,f) = expression b in
			(a, e, (Div c f))
        (Exp_tk, l0):tl -> 
   			let (a,b,c) = expression tl in
   			let (d,e,f) = expression b in
			(a, e, (Expo c f))

{-		(Integer_tk, l0):(Id_tk v, l1):(PV_tk, l2):tl ->
			(True, tl, (Variable v))
		(Real_tk, l0):(Id_tk v, l1):(PV_tk, l2):tl ->
			(True, tl, (Variable v))
		
		(Int_tk v,l0):(Plus_tk,l1):tl ->
			let (a,b,c) = expression tl in
			(a, b, (Sum (Constant (Int_v v) Int_t) c))
		(Int_tk v,l0):(PV_tk,l1):tl ->
			(True, tl, (Constant (Int_v v) Int_t))
		(Int_tk v,l0):(Minus_tk,l1):tl ->
			let (a,b,c) = expression tl in
			(a, b, Sub (Constant (Int_v v) Int_t) c)
		(Int_tk v,l0):(Div_tk,l1):tl ->
			let (a,b,c) = expression tl in
			(a, b, Div (Constant (Int_v v) Int_t) c)
		(Int_tk v,l0):(Mult_tk,l1):tl ->
			let (a,b,c) = expression tl in
			(a, b, Mul (Constant (Int_v v) Int_t) c)
	-}		
{- Backup
expression :: [Token] -> (Bool, [Token], Expr)
expression expr =
	case expr of
		(Integer_tk, l0):(Id_tk v, l1):(PV_tk, l2):tl ->
			(True, tl, (Variable v))
		
		(Int_tk v,l0):(Plus_tk,l1):tl ->
			let (a,b,c) = expression tl in
			(a, b, Sum (Constant (Int_v v) Int_t) c)
		(Int_tk v,l0):(PV_tk,l1):tl ->
			(True, tl, (Constant (Int_v v) Int_t))
		(Int_tk v,l0):(Minus_tk,l1):tl ->
			let (a,b,c) = expression tl in
			(a, b, Sub (Constant (Int_v v) Int_t) c)
		(Int_tk v,l0):(Div_tk,l1):tl ->
			let (a,b,c) = expression tl in
			(a, b, Div (Constant (Int_v v) Int_t) c)
		(Int_tk v,l0):(Mult_tk,l1):tl ->
			let (a,b,c) = expression tl in
			(a, b, Mul (Constant (Int_v v) Int_t) c)
-}
--		_ -> (True, expr, (Constant (Int_v 0) Int_t))
